package com.dmp.onlinestore.controller;


import com.dmp.onlinestore.model.dto.ProductBean;
import com.dmp.onlinestore.model.dto.ProductBeanFilterSpec;
import com.dmp.onlinestore.model.service.Catalog;
import com.dmp.onlinestore.model.service.ProductBeanPager;
import com.dmp.onlinestore.model.service.base.ServiceExecutionException;
import com.dmp.onlinestore.model.service.base.ServiceFactory;
import com.dmp.onlinestore.system.Settings;
import com.dmp.onlinestore.view.base.ViewAddressFactory;
import com.dmp.onlinestore.view.base.ViewDefs;

import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;

public class ActionHandlerGetProducts extends ActionHandler {

	//private int targetPersonId = -1;
	
	// Variants of the getProducts action.
	public static String PARM_PAGING   = "changepage";
	
	// For "PARM_PAGING"...
	public static String PAGING_NEXT      = "next";
	public static String PAGING_PREV      = "prev";
	public static String PAGING_GOTO_PAGE = "gotoPage";
	public static String PAGING_PAGE_SIZE = "pageSize";

	// For "PAGING_GOTO_PAGE...
	public static String GOTO_TARGET = "pageNum";

	// For "PAGE_SIZE...
	public static String PAGE_NEW_SIZE = "newSize";
	
	
	private static int SUB_ACTION_ERROR               = -1;
	private static int SUB_ACTION_GET_PRODUCTS        = 0;
	private static int SUB_ACTION_PAGE_NEXT           = 1;
	private static int SUB_ACTION_PAGE_PREV           = 2;
	private static int SUB_ACTION_PAGE_GOTO           = 3;
	private static int SUB_ACTION_PAGE_SET_PATCH_SIZE = 4;
	
	private int subAction = SUB_ACTION_ERROR;
	
	private int gotoPageNum = -1;
	private int newPageSize = -1;
	
	private static String SESSION_ATTR_PAGER = "ProductBeanPager";
	
	
	public ActionHandlerGetProducts(HttpServletRequest request, HttpServletResponse response) {
		super(request, response);
	}
	
	private int getSubAction() {
		return subAction;
	}
	private int getGotoPageNum() {
		return gotoPageNum;
	}
	private int getNewPageSize() {
		return newPageSize;
	}
	
	private void setSubAction(int subAction) {
		this.subAction = subAction;
	}
	
	public void validate()  throws ControllerValidationException {
		assertMaxNumMapEntries(3, INTERNAL_ASSERTION);
		int numParms = getNumRequestParms();
		if (numParms == 1) {
			setSubAction(SUB_ACTION_GET_PRODUCTS);
		}
		else if (getNumRequestParms() == 2) {
			String[] pagingParm = assertParmPresent(PARM_PAGING, 1, INTERNAL_ASSERTION);
			if (pagingParm[0].equals(PAGING_NEXT)) {
				System.out.println("Received a page-next");
				setSubAction(SUB_ACTION_PAGE_NEXT);
			}
			else if (pagingParm[0].equals(PAGING_PREV)) {
				System.out.println("Received a page-prev");
				setSubAction(SUB_ACTION_PAGE_PREV);
			}
		}
		else if (getNumRequestParms() == 3) {
			String[] pagingParm = assertParmPresent(PARM_PAGING, 1, INTERNAL_ASSERTION);
			if (pagingParm[0].equals(PAGING_GOTO_PAGE)) {
				String[] targetPage = assertParmPresent(GOTO_TARGET, 1, INTERNAL_ASSERTION);
				this.gotoPageNum = Integer.parseInt(targetPage[0]);
				setSubAction(SUB_ACTION_PAGE_GOTO);
			}
			else if (pagingParm[0].equals(PAGING_PAGE_SIZE)) {
				String[] pageSize = assertParmPresent(PAGE_NEW_SIZE, 1, INTERNAL_ASSERTION);
				this.newPageSize = Integer.parseInt(pageSize[0]);
				setSubAction(SUB_ACTION_PAGE_SET_PATCH_SIZE);
			}
			else {
				throw new ControllerInternalValidationException("Invalid page action.");
			}
		}
		if (getSubAction() == SUB_ACTION_ERROR) {
			throw new ControllerInternalValidationException("Invalid request.");
		}
	}

	
//	// The parm "id" must be present.
//	String idParm[] = assertParmPresent("id", 1, INTERNAL_ASSERTION);
//	
//	// The id parm must be an integer.
//	try {
//		int id = Integer.parseInt(idParm[0]);
//		setTargetPersonId(id);
//	}
//	catch (NumberFormatException e) {
//		e.printStackTrace();
//		throw new ControllerInternalValidationException("Non-integer id input parameter.");
//	}
	
	
//	private int getTargetPersonId() {
//		return this.targetPersonId;
//	}
//	private void setTargetPersonId(int id) {
//		this.targetPersonId = id;
//	}
		
	// Update this later to use application-defined (global) string constants instead
	// of hard-coded strings.
	protected void process() throws ControllerException {
		if (Settings.CONSOLE_DEBUG_ON) {
			System.out.println("ActionHandlerGetProducts::process");
		}
		// Get list of all AddressBean's and store them in the request object.
		try {
			// The list of products we'll display.
			List<ProductBean> productList = null;
			ProductBeanPager pager = null;

			int subAction = getSubAction();
			if (subAction == SUB_ACTION_GET_PRODUCTS) {
				// This is the initial query to the service to get the list 
				// of products.
				Catalog catalog = ServiceFactory.instance().getCatalog();
				
				// Use default filter (returns all products).
				pager = catalog.getProducts();

				// Put the page into our session so that we can handle
				// future paging events from the user.
				getRequest().getSession().setAttribute(SESSION_ATTR_PAGER, pager);
				
				// Get the list of products to display and the indices into the pages.
				productList = pager.pageDown();
			}
			else if (subAction == SUB_ACTION_PAGE_NEXT) {
				// We already have a list of products previously queried. Get the
				// next page of product (page down).

				// Get the pager.
				pager = (ProductBeanPager) getRequest().getSession().getAttribute(SESSION_ATTR_PAGER);
				
				if (pager == null) {
					throw new ControllerExecutionException("Service logic experienced an exception; no pager in session");
				}
				
				// Get the initial list of products to display.
				productList = pager.pageDown();
			}
			else if (subAction == SUB_ACTION_PAGE_PREV) {
				// We already have a list of products previously queried. Get the
				// next page of product (page down).

				// Get the pager.
				pager = (ProductBeanPager) getRequest().getSession().getAttribute(SESSION_ATTR_PAGER);
				
				if (pager == null) {
					throw new ControllerExecutionException("Service logic experienced an exception; no pager in session");
				}
				
				// Get the initial list of products to display.
				productList = pager.pageUp();
			}
			else if (subAction == SUB_ACTION_PAGE_GOTO) {
				// We already have a list of products previously queried. Get the
				// next page of product (page down).

				// Get the pager.
				pager = (ProductBeanPager) getRequest().getSession().getAttribute(SESSION_ATTR_PAGER);
				
				if (pager == null) {
					throw new ControllerExecutionException("Service logic experienced an exception; no pager in session");
				}
				int targetPage = getGotoPageNum();
				// Get the initial list of products to display.
				productList = pager.goToPage(targetPage);
			}
			else if (subAction == SUB_ACTION_PAGE_SET_PATCH_SIZE) {
				// Set the new page size.
				pager = (ProductBeanPager) getRequest().getSession().getAttribute(SESSION_ATTR_PAGER);
				
				if (pager == null) {
					throw new ControllerExecutionException("Service logic experienced an exception; no pager in session");
				}
				int newPageSize = this.getNewPageSize();
				productList = pager.setPageSize(newPageSize);
				
				// Mimic the behavior of automomatically moving to first page when
				// the page size is set to a new value.
				productList = pager.goToPage(1);
			}
			
			// Get the index list to display.
			List<String> indicesList = pager.getPageIndices();

			// Pass the list of products and the indices list to the catalog view.
			getRequest().setAttribute(ViewDefs.ATTR_PRODUCT_LIST, productList);
			getRequest().setAttribute(ViewDefs.ATTR_INDEX_LIST, indicesList);
			getRequest().setAttribute(ViewDefs.ATTR_CURR_RANGE, pager.getCurrentPageRange());
		    String viewAddress = ViewAddressFactory.instance().getCatalog();
			RequestDispatcher dispatcher = getRequest().getRequestDispatcher(viewAddress);
			dispatcher.forward(getRequest(), getResponse());
		}
		catch (ServiceExecutionException e) {
			throw new ControllerExecutionException("Service logic experienced an exception");
		}		
		catch (ServletException e) {
			e.printStackTrace();
			throw new ControllerExecutionException("Controller experienced a ServletException!!");
		}
		catch (IOException e) {
			e.printStackTrace();
			throw new ControllerExecutionException("Controller experienced an IOException!!");
		}		
	}
}
